import * as React from "react";
import "./index.scss"
import {
    useFloating,
    autoUpdate,
    offset,
    flip,
    shift,
    useHover,
    useFocus,
    useDismiss,
    useRole,
    useInteractions,
    useMergeRefs,
    FloatingPortal,
    arrow
} from "@floating-ui/react";
import type {Placement} from "@floating-ui/react";

interface TooltipOptions {
    initialOpen?: boolean;
    placement?: Placement;
    open?: boolean;
    onOpenChange?: (open: boolean) => void;
}

export function useTooltip({
                               initialOpen = false,
                               placement = "top",
                               open: controlledOpen,
                               onOpenChange: setControlledOpen
                           }: TooltipOptions = {}) {
    const [uncontrolledOpen, setUncontrolledOpen] = React.useState(initialOpen);
    const arrowRef = React.useRef<HTMLDivElement>(null);

    const open = controlledOpen ?? uncontrolledOpen;
    const setOpen = setControlledOpen ?? setUncontrolledOpen;

    const data = useFloating({
        placement,
        open,
        onOpenChange: setOpen,
        whileElementsMounted: autoUpdate,
        middleware: [
            offset(20),
            flip({
                crossAxis: placement.includes("-"),
                fallbackAxisSideDirection: "start",
                padding: 5
            }),
            shift({padding: 5}),
            arrow({
                element: arrowRef,
                padding: 5,

            })
        ]
    });

    const context = data.context;

    const hover = useHover(context, {
        move: false,
        enabled: controlledOpen == null
    });
    const focus = useFocus(context, {
        enabled: controlledOpen == null
    });
    const dismiss = useDismiss(context);
    const role = useRole(context, {role: "tooltip"});

    const interactions = useInteractions([hover, focus, dismiss, role]);

    return React.useMemo(
        () => ({
            open,
            setOpen,
            ...interactions,
            ...data,
            arrowRef
        }),
        [open, setOpen, interactions, data]
    );
}

type ContextType = ReturnType<typeof useTooltip> | null;

const TooltipContext = React.createContext<ContextType>(null);

export const useTooltipContext = () => {
    const context = React.useContext(TooltipContext);

    if (context == null) {
        throw new Error("Tooltip components must be wrapped in <Tooltip />");
    }

    return context;
};

export function Tooltip({
                            children,
                            ...options
                        }: { children: React.ReactNode } & TooltipOptions) {
    // This can accept any props as options, e.g. `placement`,
    // or other positioning options.
    const tooltip = useTooltip(options);
    return (
        <TooltipContext.Provider value={tooltip}>
            {children}
        </TooltipContext.Provider>
    );
}

export const TooltipTrigger = React.forwardRef<
    HTMLElement,
    React.HTMLProps<HTMLElement> & { asChild?: boolean }
>(function TooltipTrigger({children, asChild = false, ...props}, propRef) {
    const context = useTooltipContext();

    // 正确处理 ref 类型
    const childrenRef = React.isValidElement(children)
        ? (children as React.ReactElement & { ref?: React.Ref<HTMLElement> }).ref
        : undefined;

    const ref = useMergeRefs([context.refs.setReference, propRef, childrenRef]);

    // `asChild` allows the user to pass any element as the anchor
    if (asChild && React.isValidElement(children)) {
        const referenceProps = {
            ...context.getReferenceProps(props),
            ref,
            ...(children.props as Record<string, unknown>),
            "data-state": context.open ? "open" : "closed"
        } as const;

        return React.cloneElement(children, referenceProps);
    }

    return (
        <>
            <div
                ref={ref}
                data-state={context.open ? "open" : "closed"}
                {...context.getReferenceProps(props)}
            >
                {children}
            </div>
        </>

    );
});

export const TooltipContent = React.forwardRef<
    HTMLDivElement,
    React.HTMLProps<HTMLDivElement>
>(function TooltipContent({style, ...props}, propRef) {
    const context = useTooltipContext();
    const ref = useMergeRefs([context.refs.setFloating, propRef]);

    if (!context.open) return null;

    const floatingProps = context.getFloatingProps(props);
    const mergedStyle = {
        ...(context.floatingStyles as Record<string, unknown>),
        ...(style as Record<string, unknown>)
    };

    // 计算箭头位置
    const arrowStyle: React.CSSProperties = {
        ...context.middlewareData.arrow,
        zIndex: -1,
        position: 'absolute' as const,
        width: '16px',
        height: '16px',
        background: 'inherit',
        transform: 'rotate(45deg)',
        left: context.middlewareData.arrow?.x ? `${context.middlewareData.arrow.x + 8}px` : '50%',
        top: context.middlewareData.arrow?.y ? `${context.middlewareData.arrow.y}px` : '100%',
        marginLeft: '-0.5rem',
        marginTop: '-0.5rem'
    };

    return (
        <FloatingPortal>
            <div
                className="Tooltip"
                ref={ref}
                style={mergedStyle}
                {...floatingProps}
            >
                {props.children}
                <div
                    ref={context.arrowRef}
                    className="tooltip-arrow"
                    style={arrowStyle}
                />
            </div>
        </FloatingPortal>
    );
});
